﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
using NetPE.Core.Metadata;
using NetPE.TreeNodes;
using System.Globalization;
using NetPE.Dialogs;
using NetPE.Core.Metadata.Tables;

namespace NetPE
{
    class MdRowEditor : BaseEditor
    {
        TableLayoutPanel panel;
        FlowLayoutPanel actPanel;

        public MdRowEditor()
        {
            this.DoubleBuffered = true;
            panel = new TableLayoutPanel();
            panel.ColumnCount = 3;
            panel.Location = Point.Empty;
            panel.AutoSize = true;
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 175));
            panel.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
            panel.Padding = new Padding(5);

            actPanel = new FlowLayoutPanel();
            actPanel.AutoScroll = true;
            actPanel.FlowDirection = FlowDirection.TopDown;
            actPanel.Padding = new Padding(5);
            actPanel.Dock = DockStyle.Fill;

            this.Controls.Add(actPanel);
            actPanel.Controls.Add(panel);
        }
        protected override void RefreshData()
        {
            this.SuspendLayout();
            actPanel.SuspendLayout();
            panel.SuspendLayout();

            actPanel.Controls.Clear();
            actPanel.Controls.Add(panel);
            panel.Controls.Clear();

            MetadataRow row = Object as MetadataRow;
            MetadataTable tbl = row.Container;

            MetadataColumn[] cols = tbl.Columns;
            panel.RowCount = 1 + cols.Length;

            panel.Controls.Add(new Label() { Text = "Name", Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 0, 0);
            panel.Controls.Add(new Label() { Text = "Type", Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 1, 0);
            panel.Controls.Add(new Label() { Text = "Value", Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 2, 0);
            for (int i = 0; i < cols.Length; i++)
            {
                panel.Controls.Add(new Label() { Text = cols[i].Name, Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 0, i + 1);
                if(cols[i].Type is Type)
                    panel.Controls.Add(new Label() { Text = (cols[i].Type as Type).Name, Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 1, i + 1);
                else
                    panel.Controls.Add(new Label() { Text = cols[i].Type.ToString(), Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 1, i + 1);

                if (!(cols[i].Type is Type))
                {
                    MetadataTokenEditor mte = new MetadataTokenEditor((row[i] as TableToken).Token);
                    mte.Anchor = AnchorStyles.None;
                    mte.ValueChanged += new EventHandler(PropChanged);
                    mte.Tag = i;
                    panel.Controls.Add(mte, 2, i + 1);
                }
                else
                {

                    TextBox tb;
                    switch ((cols[i].Type as Type).FullName)
                    {
                        case "NetPE.Core.Rva":
                            tb = new TextBox();
                            tb.BackColor = Color.Black;
                            tb.ForeColor = Color.White;
                            tb.BorderStyle = BorderStyle.None;
                            tb.TextAlign = HorizontalAlignment.Center;
                            tb.Width = 200;
                            tb.Anchor = AnchorStyles.None;
                            tb.Text = row[i].ToString();
                            tb.LostFocus += new EventHandler(PropChanged);
                            tb.Tag = i;
                            panel.Controls.Add(tb, 2, i + 1);
                            break;
                        case "System.Byte":
                            tb = new TextBox();
                            tb.BackColor = Color.Black;
                            tb.ForeColor = Color.White;
                            tb.BorderStyle = BorderStyle.None;
                            tb.TextAlign = HorizontalAlignment.Center;
                            tb.Width = 200;
                            tb.Anchor = AnchorStyles.None;
                            tb.Text = ((byte)row[i]).ToString("x2");
                            tb.LostFocus += new EventHandler(PropChanged);
                            tb.Tag = i;
                            panel.Controls.Add(tb, 2, i + 1);
                            break;
                        case "System.UInt16":
                            tb = new TextBox();
                            tb.BackColor = Color.Black;
                            tb.ForeColor = Color.White;
                            tb.BorderStyle = BorderStyle.None;
                            tb.TextAlign = HorizontalAlignment.Center;
                            tb.Width = 200;
                            tb.Anchor = AnchorStyles.None;
                            tb.Text = ((ushort)row[i]).ToString("x4");
                            tb.LostFocus += new EventHandler(PropChanged);
                            tb.Tag = i;
                            panel.Controls.Add(tb, 2, i + 1);
                            break;
                        case "System.UInt32":
                            tb = new TextBox();
                            tb.BackColor = Color.Black;
                            tb.ForeColor = Color.White;
                            tb.BorderStyle = BorderStyle.None;
                            tb.TextAlign = HorizontalAlignment.Center;
                            tb.Width = 200;
                            tb.Anchor = AnchorStyles.None;
                            tb.Text = ((uint)row[i]).ToString("x8");
                            tb.LostFocus += new EventHandler(PropChanged);
                            tb.Tag = i;
                            panel.Controls.Add(tb, 2, i + 1);
                            break;
                        case "System.UInt64":
                            tb = new TextBox();
                            tb.BackColor = Color.Black;
                            tb.ForeColor = Color.White;
                            tb.BorderStyle = BorderStyle.None;
                            tb.TextAlign = HorizontalAlignment.Center;
                            tb.Width = 200;
                            tb.Anchor = AnchorStyles.None;
                            tb.Text = ((ulong)row[i]).ToString("x16");
                            tb.LostFocus += new EventHandler(PropChanged);
                            tb.Tag = i;
                            panel.Controls.Add(tb, 2, i + 1);
                            break;
                        default:
                            Button btn = new Button();
                            btn.FlatStyle = FlatStyle.Popup;
                            btn.Anchor = AnchorStyles.None;
                            btn.Dock = DockStyle.Fill;
                            btn.Text = (cols[i].Type as Type).Name;
                            btn.Click += new EventHandler(ShowEditDialog);
                            btn.Tag = i;
                            panel.Controls.Add(btn, 2, i + 1);
                            break;
                    }
                }
            }
            for (int i = 0; i < panel.RowCount; i++)
                panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));


            panel.ResumeLayout();
            actPanel.ResumeLayout();
            this.ResumeLayout();
        }

        bool onevent = false;
        private void PropChanged(object sender, EventArgs e)
        {
            if (!onevent)
            {
                int i = (int)(sender as Control).Tag;
                MetadataRow row = Object as MetadataRow;
                MetadataColumn col = row.Container.Columns[i];
                string val = (sender as Control).Text;

                if (!(col.Type is Type))
                {
                    row[i] = new TableToken(row.Container.Heap, (sender as MetadataTokenEditor).Object as MetadataToken );
                    return;
                }
                
                switch ((col.Type as Type).FullName)
                    {
                        case "NetPE.Core.Rva":
                            if (val.TrimStart('0').Length > 8) break;
                            row[i] = (NetPE.Core.Rva)uint.Parse(val, NumberStyles.HexNumber);
                            break;
                        case "System.Byte":
                            if (val.TrimStart('0').Length > 2) break;
                            row[i] = byte.Parse(val, NumberStyles.HexNumber);
                            break;
                        case "System.UInt16":
                            if (val.TrimStart('0').Length > 4) break;
                            row[i] = ushort.Parse(val, NumberStyles.HexNumber);
                            break;
                        case "System.UInt32":
                            if (val.TrimStart('0').Length > 8) break;
                            row[i] = uint.Parse(val, NumberStyles.HexNumber);
                            break;
                        case "System.UInt64":
                            if (val.TrimStart('0').Length > 16) break;
                            row[i] = ulong.Parse(val, NumberStyles.HexNumber);
                            break;
                        case "NetPE.Core.Metadata.MetadataToken":
                            row[i] = (sender as MetadataTokenEditor).Object;
                            break;
                        default: throw new InvalidOperationException();
                    }

                onevent = true;
                switch ((col.Type as Type).FullName)
                {
                    case "NetPE.Core.Rva":
                        (sender as Control).Text = row[i].ToString();
                        break;
                    case "System.Byte":
                        (sender as Control).Text = ((byte)row[i]).ToString("x2");
                        break;
                    case "System.UInt16":
                        (sender as Control).Text = ((ushort)row[i]).ToString("x4");
                        break;
                    case "System.UInt32":
                        (sender as Control).Text = ((uint)row[i]).ToString("x8");
                        break;
                    case "System.UInt64":
                        (sender as Control).Text = ((ulong)row[i]).ToString("x16");
                        break;
                    case "NetPE.Core.Metadata.MetadataToken":
                        break;
                    default: throw new InvalidOperationException();
                }
                onevent = false;
            }
        }

        private void ShowEditDialog(object sender, EventArgs e)
        {
            int i = (int)(sender as Control).Tag;
            MetadataRow row = Object as MetadataRow;
            MetadataColumn col = row.Container.Columns[i];
            object old = row[col.Index];
            try
            {
                if ((col.Type as Type).IsEnum)
                {
                    BaseDialog dialog = null;
                    if ((col.Type as Type).IsDefined(typeof(FlagsAttribute), true))
                        (dialog = new FlagEnumDialog(row[i])).ShowDialog();
                    else
                        (dialog = new EnumDialog(row[i])).ShowDialog();
                    row[i] = dialog.Object;
                }
                else
                {
                    new TokenDialog(row, col).ShowDialog();
                }
            }
            catch
            {
                MessageBox.Show("Error!!");
                row[col.Index] = old;
            }

        }
    }
}
